package cmd

import (
	"io"

	common "cke.io/ckectl/app/cmd/phases"
	phases "cke.io/ckectl/app/cmd/phases/scale"
	"cke.io/ckectl/app/constants"
	kubeadmutil "cke.io/ckectl/app/util"
	"github.com/spf13/cobra"
	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow"
)

// NewCmdInit returns "kubeadm init" command.
// NB. initOptions is exposed as parameter for allowing unit testing of
//     the newInitOptions method, that implements all the command options validation logic
func NewCmdScale(out io.Writer, prepareOptions *prepareOptions) *cobra.Command {
	if prepareOptions == nil {
		prepareOptions = newPrepareOptions()
	}
	prepareRunner := workflow.NewRunner()

	cmd := &cobra.Command{
		Use:   "scale",
		Short: "Run this command in order to prepare files for the Kubernetes Deploy",
		Run: func(cmd *cobra.Command, args []string) {
			c, err := prepareRunner.InitData(args)
			kubeadmutil.CheckErr(err)

			data := c.(*prepareData)
			// fmt.Printf("[prepare] Using Kubernetes version: %s\n", data.cfg.KubernetesVersion)

			// flase done file when start up
			common.FlashAndSetDoneFile(constants.AnsibleScaleDoneFile)

			err = prepareRunner.Run(args)
			kubeadmutil.CheckErr(err)
			_ = common.WritePhaseDoneMsg("", "", data.cfg, nil)

			err = showPrepareResult(prepareRunner, data, out)
			kubeadmutil.CheckErr(err)
		},
		Args: cobra.NoArgs,
	}

	// adds flags to the init command
	// init command local flags could be eventually inherited by the sub-commands automatically generated for phases
	AddPrepareConfigFlags(cmd.Flags(), prepareOptions.externalClusterCfg, prepareOptions.externalCkeCfg)
	AddPrepareOtherFlags(cmd.Flags(), prepareOptions)

	// initialize the workflow runner with the list of phases
	for _, phase := range GetScalePhase() {
		prepareRunner.AppendPhase(phase)
	}
	SetPhasesFlags(prepareRunner.Phases, GetFlagSetNames(cmd.Flags())...)

	// sets the data builder function, that will be used by the runner
	// both when running the entire workflow or single phases
	prepareRunner.SetDataInitializer(func(cmd *cobra.Command, args []string) (workflow.RunData, error) {
		return newPrepareData(cmd, args, prepareOptions, out)
	})

	// binds the Runner to kubeadm init command by altering
	// command help, adding --skip-phases flag and by adding phases subcommands
	prepareRunner.BindToCommand(cmd)

	return cmd
}

func GetScalePhase() []workflow.Phase{
	return []workflow.Phase {
		phases.NewIptabelsScalePhase(),
		phases.NewEtcdScalePhase(),
		phases.NewUpdateEtchostsPhase(),
		phases.NewScalePhase(),
		phases.NewMasterScalePhase(),
		phases.NewMonitorsPhase(),
		phases.NewAfterScaleUpPhase(),
	}
}
